/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_TOOLS_TYPES_RELATION_METADATA_HPP
#define	_CUBEFS_CORE_TOOLS_TYPES_RELATION_METADATA_HPP

#include <cubefs/core/tools/types/typelist.hpp>
#include <cubefs/core/tools/types/algo.hpp>
#include <cubefs/core/tools/assert.hpp>

namespace cubefs    {
namespace tools     {

template <Int Name_, typename Type_ = NullType>
struct Column {
    static const Int    Name = Name_;
    typedef Type_       Type;
};

template <typename T>
struct IsColumn: public FalseValue {};

template <Int Name, typename T>
struct IsColumn<Column<Name, T> >: public TrueValue {};


template <typename ColumnType, typename TypeValue_>
struct TypeValue {
    typedef TypeValue_  Value;
    typedef ColumnType  Column;
};

template <typename ColumnType, typename ColumnType::Type Value_>
struct StaticValue {
    static const typename ColumnType::Type Value = Value_;
    typedef ColumnType Column;
};


template <Int Name> class ColumnNotFound;

template <Int Name, typename ColumnsList>
class FindColumn {

    CUBEFS_STATIC_ASSERT(IsNonemptyList<ColumnsList>::Value);

    template <typename Config, typename Item, typename Accumulator>
    struct Handler {
        static const bool Equal = Item::Name == Name;
        
        typedef typename IfThenElse<
                    Equal,
                    Item,
                    typename Accumulator::Result
        >::Result                                                               Result;
    };

    struct Init {
        typedef NullType Result;
    };

    typedef typename ForEach<
                NullType,
                ColumnsList,
                Handler,
                Init
    >::Result::Result                                                           Result0;

    static const bool Found = !IfTypesEqual<Result0, NullType>::Value;

public:

    typedef typename IfThenElse<Found, Result0, ColumnNotFound<Name> >::Result  Result;
};



template <
        typename ColumnsList,
        template <Int Name, typename ColumnType, typename Record> class ValueProvider
>
class RelationMetadata {
    CUBEFS_STATIC_ASSERT(IsNonemptyList<ColumnsList>::Value);
public:
    typedef ColumnsList List;
    template <Int Name, typename Record>
    class Provider {
        typedef typename FindColumn<Name, ColumnsList>::Result ColumnType;
    public:
        typedef ValueProvider<Name, ColumnType, Record>                         Value;
    };
};


template <typename T> struct IsRelationMetadata: public FalseValue {};

template <
        typename ColumnsList,
        template <Int Name, typename ColumnType, typename Record> class ValueProvider
>
struct IsRelationMetadata<RelationMetadata<ColumnsList, ValueProvider> >: public TrueValue {};

}
}

#endif //_CUBEFS_CORE_TOOLS_TYPES_RELATION_METADATA_HPP